package com.zcbl.toolkit.util;

import com.zcbl.toolkit.exception.SystemRuntimeException;
import net.coobird.thumbnailator.Thumbnails;
import net.coobird.thumbnailator.filters.Watermark;
import net.coobird.thumbnailator.geometry.Positions;
import org.springframework.util.Assert;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.UUID;

/**
 * @author he peng
 * @create 2018/4/25 14:08
 * @see
 */
public class ImageUtils {

    private ImageUtils() {}

    /**
     * 对图片压缩
     * @param source    图片源
     * @param scale     压缩后图片的大小
     * @param outputQuality     输出的图片质量
     * @param dest  图片的输出
     */
    public static void fastImageCompress(InputStream source , double scale ,
                                         double outputQuality , OutputStream dest) {
        Assert.notNull(source , "source == null");
        Assert.notNull(dest , "dest == null");
        com.zcbl.toolkit.util.Assert.range(0.0 , 1.0 , scale , "scale < 0.0 or scale > 1.0");
        com.zcbl.toolkit.util.Assert.range(0.0 , 1.0 , outputQuality , "outputQuality < 0.0 or outputQuality > 1.0");
        try {
            Thumbnails.of(source)
                    .scale(scale)
                    .outputQuality(outputQuality)
                    .outputFormat("jpeg")
                    .toOutputStream(dest);
        } catch (IOException e) {
            throw new SystemRuntimeException("Fast Image Compress Error" , e);
        }
    }

    public static void fastImageCompress(BufferedImage source , double scale ,
                                         double outputQuality , OutputStream dest) {
        Assert.notNull(source , "source == null");
        Assert.notNull(dest , "dest == null");
        com.zcbl.toolkit.util.Assert.range(0.0 , 1.0 , scale , "scale < 0.0 or scale > 1.0");
        com.zcbl.toolkit.util.Assert.range(0.0 , 1.0 , outputQuality , "outputQuality < 0.0 or outputQuality > 1.0");
        try {
            Thumbnails.of(source)
                    .scale(scale)
                    .outputQuality(outputQuality)
                    .outputFormat("jpeg")
                    .toOutputStream(dest);
        } catch (IOException e) {
            throw new SystemRuntimeException("Fast Image Compress Error" , e);
        }
    }

    public static String uuidFileName(String format) {
        format = org.apache.commons.lang3.StringUtils.defaultIfEmpty(format, "");
        return UUID.randomUUID().toString().replace("-" , "") + "." + format;
    }

    /**
     * 快速加水印
     * @param source
     * @param watermarkImage
     * @param scale
     * @param outputQuality
     * @param watermarkContent
     * @return
     */
    public static FastWatermarkResult fastWatermark(InputStream source , BufferedImage watermarkImage ,
                                                    double scale , double outputQuality , WatermarkContent watermarkContent) {
        Assert.notNull(source , "source == null");
        Assert.notNull(watermarkImage , "watermarkImage == null");
        Assert.notNull(watermarkContent , "watermarkContent == null");
        com.zcbl.toolkit.util.Assert.range(0.0 , 1.0 , scale , "scale < 0.0 or scale > 1.0");
        com.zcbl.toolkit.util.Assert.range(0.0 , 1.0 , outputQuality , "outputQuality < 0.0 or outputQuality > 1.0");
        try {
            BufferedImage image = ImageIO.read(source);
            ByteArrayOutputStream originalImageOutputStream = new ByteArrayOutputStream();
            fastImageCompress(image , scale , outputQuality , originalImageOutputStream);
            FastWatermarkResult.FastWatermarkResultBuilder fastWatermarkResultBuilder =
                    FastWatermarkResult.builder().originalImageOutputStream(originalImageOutputStream);

            ByteArrayOutputStream watermarkImageOutputStream = new ByteArrayOutputStream();
            watermark(watermarkImage , image , scale , outputQuality ,
                    watermarkContent , originalImageOutputStream , watermarkImageOutputStream);
            fastWatermarkResultBuilder.watermarkImageOutputStream(watermarkImageOutputStream);
            return fastWatermarkResultBuilder.build();
        } catch (IOException e) {
            throw new SystemRuntimeException("Fast Image watermark Error" , e);
        }
    }

    private static void watermark(BufferedImage watermarkImage , BufferedImage image ,
                                  double scale , double outputQuality , WatermarkContent watermarkContent ,
                                  ByteArrayOutputStream originalImageOutputStream , ByteArrayOutputStream watermarkImageOutputStream) {
        try {
            Watermark watermark = new Watermark(Positions.TOP_LEFT , watermarkImage , 1);
            image = Thumbnails.of(image).scale(1).watermark(watermark).asBufferedImage();

            Graphics2D graphics = image.createGraphics();
            int fontSize = 15;
            graphics.setFont(new Font("黑体", Font.BOLD, fontSize));
            graphics.setColor(new Color(245,127,32));
            graphics.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, 1f));
            int watermarkImgWidth = watermarkImage.getWidth(null);
            String formatTime = "时间:" + watermarkContent.getTime();
            graphics.drawString(formatTime , watermarkImgWidth + 5 , fontSize + 9);
            graphics.drawString("地址:" + watermarkContent.getAddress(), watermarkImgWidth + StringUtils.getLength(formatTime) + 210, fontSize + 9);
            byte[] originalImageBytes = originalImageOutputStream.toByteArray();
            String md5EncodeHex = Md5Utils.md5EncodeHex(originalImageBytes, 0, originalImageBytes.length / 2);
            graphics.drawString("MD5:" + md5EncodeHex , watermarkImgWidth + 5 , fontSize * 2 + 9);
            graphics.dispose();
            fastImageCompress(image , scale , outputQuality , watermarkImageOutputStream);
        } catch (IOException e) {
            throw new SystemRuntimeException("Fast Image watermark Error" , e);
        }
    }

}
